package cz.muni.fi.pa165.sme.web.pages.user;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import cz.muni.fi.pa165.sme.api.UserService;
import cz.muni.fi.pa165.sme.api.to.UserTO;
import cz.muni.fi.pa165.sme.web.common.TrackerDataTable;
import cz.muni.fi.pa165.sme.web.converters.ConvertUtils;
import cz.muni.fi.pa165.sme.web.fo.UserFO;
import cz.muni.fi.pa165.sme.web.pages.TemplatePage;
import cz.muni.fi.pa165.sme.web.panels.ClickablePropertyColumn;
import cz.muni.fi.pa165.sme.web.panels.DeletePanel;
import cz.muni.fi.pa165.sme.web.panels.EditPanel;
import cz.muni.fi.pa165.sme.web.security.Authorizer;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeAction;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.core.convert.ConversionService;

/**
 * @author jirankova
 */
@AuthorizeAction(action = Action.RENDER, roles = { Roles.ADMIN, Roles.USER})
public class UserListPage extends TemplatePage {

	@SpringBean
	private UserService userService;

	@SpringBean(name = "conversionServiceFe")
	private ConversionService conversionService;

	public UserListPage() {
		//page title
		add(new Label("title", new ResourceModel("user.list.title")));

		//table containing users
		final WebMarkupContainer table = new TrackerDataTable<UserFO>("table", getColumns(), new UserDataProvider(
				ConvertUtils.convertList(userService.findAllUserTO(), conversionService, UserFO.class)));
		table.setOutputMarkupId(true);
		add(table);
	}

	/**
	 * Columns for user table
	 *
	 * @return list of columns
	 */
	private List<IColumn<UserFO>> getColumns() {
		final List<IColumn<UserFO>> columns = new ArrayList<IColumn<UserFO>>();

		//user name (both first and last name)
		columns.add(new ClickablePropertyColumn<UserFO>(new ResourceModel("user.name"), "firstName") {
			@Override
			protected void onClick(final IModel<UserFO> rowModel) {
				setResponsePage(new UserDetailPage(rowModel.getObject()));
			}

			@Override
			public void populateItem(final Item<ICellPopulator<UserFO>> cellItem, final String componentId,
					final IModel<UserFO> rowModel) {
				cellItem.add(new Label(componentId,
						rowModel.getObject().getLastName() + ", " + rowModel.getObject().getFirstName()));
			}
		});

		//sex
		columns.add(new PropertyColumn<UserFO>(new ResourceModel("user.sex"), "sex") {
			@Override
			public void populateItem(final Item<ICellPopulator<UserFO>> item, final String componentId,
					final IModel<UserFO> rowModel) {
				item.add(new Label(componentId, new ResourceModel(rowModel.getObject().getSex().getName())));
			}
		});

		//date of birth
		columns.add(new PropertyColumn<UserFO>(new ResourceModel("user.birthDate"), "dateOfBirth") {
			@Override
			public void populateItem(final Item<ICellPopulator<UserFO>> item, final String componentId,
					final IModel<UserFO> rowModel) {
				item.add(new Label(componentId, DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale()).format(rowModel.getObject().getDateOfBirth())));
			}
		});

		if(Authorizer.isAdminLogged()){
			columns.add(new EditColumn(new ResourceModel("edit")));
			columns.add(new RemoveColumn(new ResourceModel("remove")));
		}

		return columns;
	}

	private class EditColumn extends AbstractColumn<UserFO> {
		private EditColumn(final IModel<String> displayModel) {
			super(displayModel);
		}

		@Override
		public void populateItem(final Item<ICellPopulator<UserFO>> cellItem, final String componentId,
				final IModel<UserFO> rowModel) {
			cellItem.add(new EditPanel(componentId, rowModel) {
				@Override
				public void onEdit() {
					setResponsePage(new UserEditPage(rowModel.getObject()));
				}
			});
		}
	}

	/**
	 * Class to create remove user column
	 */
	private class RemoveColumn extends AbstractColumn<UserFO> {
		public RemoveColumn(final IModel<String> model) {
			super(model);
		}

		@Override
		public void populateItem(final Item<ICellPopulator<UserFO>> cellItem, final String componentId,
				final IModel<UserFO> rowModel) {
			cellItem.add(new DeletePanel(componentId, rowModel) {
				@Override
				public void onDelete() {
					final UserTO userTO = conversionService.convert(rowModel.getObject(), UserTO.class);
					if (userService.isReferenced(userTO)) {
						setResponsePage(new UserDetailPage(rowModel.getObject(), "user.referenced"));
					} else {
						userService.deleteUserTO(userTO);
						setResponsePage(UserListPage.class);
					}
				}
			});
		}
	}

	/**
	 * Provides data for user table
	 */
	private class UserDataProvider extends SortableDataProvider<UserFO> {
		final List<UserFO> userFOs;

		public UserDataProvider(final List<UserFO> list) {
			userFOs = list;
		}

		@Override
		public Iterator<? extends UserFO> iterator(final int first, final int count) {
			return userFOs.subList(first, first + count).iterator();
		}

		@Override
		public int size() {
			return userFOs.size();
		}

		@Override
		public IModel<UserFO> model(final UserFO object) {
			return new CompoundPropertyModel<UserFO>(new LoadableDetachableModel<UserFO>() {
				@Override
				protected UserFO load() {
					return object;
				}
			});
		}
	}
}
